/*
 * =====================================================================================
 *
 *       Filename:  particles.cpp
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  09.02.2010 16:14:24
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Michal Antonczak (uzyszkodnik), uzyszkodnik.priv@gmail.com
 *        Company:  
 *
 * =====================================================================================
 */

#include	<SDL/SDL.h>
#include	<stdlib.h>
#include	<list>
#include	<time.h>
#include	"wektor.h"
#include	"timer.h"
#include	"particles.h"

using namespace std;
void putpixel_rgb(SDL_Surface *surf,int x, int y, Uint32 rgbzor){

   // Uint32 pixel= SDL_MapRGB(surf->format, R, G, B);
      Uint32 pixel = rgbzor;

    int bpp = surf->format->BytesPerPixel;
    /* Obliczamy adres pixela */
    Uint8 *p = (Uint8 *)surf->pixels + y * surf->pitch + x * bpp;

    switch(bpp)
    {
        case 1: //8-bit
            *p = pixel;
            break;

        case 2: //16-bit
            *(Uint16 *)p = pixel;
            break;

        case 3: //24-bit
            if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
                p[0] = (pixel >> 16) & 0xff;
                p[1] = (pixel >> 8) & 0xff;
                p[2] = pixel & 0xff;
            } else {
                p[0] = pixel & 0xff;
                p[1] = (pixel >> 8) & 0xff;
                p[2] = (pixel >> 16) & 0xff;
            }
            break;

        case 4: //32-bit
            *(Uint32 *)p = pixel;
            break;
    }


}


// b > a

float rand_float(float a, float b)
{
	return ((b-a)*((float)rand()/RAND_MAX))+a;
}

ParticleEngine::ParticleEngine(SDL_Surface* scr, SDL_Surface* cm){
/*  int mapzor[7][7] = {
		{000,000,251,252,251,000,000},
		{000,251,252,253,252,251,000},
		{251,252,253,254,253,252,251},
		{252,253,254,255,254,253,252},
		{251,252,253,254,253,252,251},
		{000,251,252,253,252,251,000},
		{000,000,251,252,251,000,000},

	};
*/
	screen = scr;
	collision_map = cm;

	Uint32 colorz[256];
	int i,j,k; 
	Uint32 colorkey;

	for(i=0;i<128;i++)
		colorz[i] = SDL_MapRGB(screen->format, i*2,i,2);
	for(i=0;i<64;i++)
		colorz[i+128] = SDL_MapRGB(screen->format, 254,i+127,i+2); 
	for(i=0;i<66;i++)
		colorz[i+190]=SDL_MapRGB(screen->format, 254,i+190,i+65);

	SDL_Rect coords;

	int locked = 0;
	for(i=255;i>=0;i--){

//		particles_forms[i] = SDL_CreateRGBSurface(SDL_HWSURFACE, 7,7,32,0,0,0,0);
		particles_forms[i] = SDL_CreateRGBSurface(SDL_HWSURFACE, 1,1,32,0,0,0,0);

		if(SDL_MUSTLOCK(particles_forms[i])){
			if(SDL_LockSurface(particles_forms[i])<=0)
				exit(1);		
			locked=1;
		}
/*  
		for(j=0;j<7;j++)
			for(k=0;k<7;k++){

					putpixel_rgb(particles_forms[i],j,k,colorz[mapzor[j][k]]);	

					if(mapzor[j][k])
						mapzor[j][k]--;
			
		}
*/

		putpixel_rgb(particles_forms[i],0,0,colorz[i]);

		if(locked){
			SDL_UnlockSurface(particles_forms[i]);
			locked=0;
		}
	}
	particles_list = new list<struct particle *>;
	dispersion = 3.14/4;
}

void ParticleEngine::emit(int num, int x, int y, Wektor v){
	int i;
	struct particle* tmp;
	float r;
	for(i=0;i<num;i++){

		tmp = new struct particle;	

		tmp->life = rand()%150+100;

		r = rand_float(0, dispersion) - dispersion/2;	
		tmp->speed.setval(v.value, v.angle+r);

		tmp->x = tmp->speed.x * rand_float(0,0.32)+x;
		tmp->y = tmp->speed.y * rand_float(0,0.32)+y;

//		tmp->x = x;
//		tmp->y = y; 
		particles_list->push_back(tmp);


	}


}


void ParticleEngine::process_particles(){
	bool locked=false;
	float tmp;
	Uint32 space_color= SDL_MapRGB(collision_map->format, 0, 0, 0);
	list <struct particle *>::iterator i;
	Uint32 *bg_color ;
	if(SDL_MUSTLOCK(collision_map)){
		SDL_LockSurface(collision_map);
		locked = true;

	}
	for(i=particles_list->begin();i!=particles_list->end();){
//		(*i)->state-=1;	

//		if((*i)->state<=0){

		(*i)->life-=rand()%20;

//		(*i)->state=1;
//
		


//		}
/*  		tmp = rand()%3;
  
		switch(tmp){
			case 0:
				if((*i)->speed.value-1<(*i)->maxdisp1);
					break;

				(*i)->speed.setval((*i)->speed.value, (*i)->speed.angle-1);
				break;
			case 1:

				if((*i)->speed.value+1>(*i)->maxdisp2)
					break;

				(*i)->speed.setval((*i)->speed.value, (*i)->speed.angle+1);
				break;
			default:
				(*i)->speed.setval((*i)->speed.value, (*i)->speed.angle);
				break;
		}
*/
		(*i)->x += (*i)->speed.x*0.16;	
		(*i)->y += (*i)->speed.y*0.16;

		if( ( (*i)->x < 0 ) || ( (*i)->x > collision_map->w) || ( (*i)->y < 0 ) || ( (*i)->y>collision_map->h) ){

			delete *i;
			i = particles_list->erase(i);
			continue;

		}

		bg_color = (Uint32 *)(collision_map->pixels+((unsigned int)(*i)->y)*collision_map->pitch+((unsigned int)(*i)->x)*collision_map->format->BytesPerPixel);

		if(((*i)->life<=0 ) || (*bg_color!=space_color)){
			delete *i;
			i = particles_list->erase(i);
			continue;
		}

		i++;

	}
	if(locked){
		SDL_UnlockSurface(collision_map);
		locked=false;
	}
	
}

void ParticleEngine::display(int x, int y){

	process_particles();

	SDL_Rect pos;
	list <struct particle *>::iterator i;


	for(i=particles_list->begin();i!=particles_list->end();i++){

		pos.x = (*i)->x;
		pos.y = (*i) -> y;

	
		pos.x-=x;
		pos.y-=y;

		if( !(pos.x>0 && pos.x < 800) )
			continue;

		if( ! (pos.y>0 && pos.y < 600))
			continue;

		/*  
		//particle just perfectly fits in the screen
		if( pos.x > 0 && pos.x < 800){
			cut.x = 0;
			cut.w = particles_forms[(*i)->life]->w;
		//left part of the particle doesn't fit	
		}  else if( (pos.x+particles_forms[(*i)->life]->w) >0 && pos.x < 800){
			cut.x = pos.x+particles_forms[(*i)->life]->w;
		        pos.x=0;	
			cut.w = particles_forms[(*i)->life]->w - cut.x;
		// right -||-
		} else if( (pos.x-particles_forms[(*i)->life]->w) < 800 && pos.x >0){
			cut.x = 0;
			cut.w = 800 - pos.x ;
		} else 
			continue;
		//particle just perfectly fits in the screen
		if( pos.y > 0 && pos.y < 600){
			cut.y = 0;
			cut.h = particles_forms[(*i)->life]->h;
		//upper part of the particle doesn't fit	
		} else if( (pos.y+particles_forms[(*i)->life]->h) >0 && pos.y < 600){
			cut.y = pos.y+particles_forms[(*i)->life]->h;
		        pos.y=0;	
			cut.h = particles_forms[(*i)->life]->h - cut.y;
		// down -||-
		} else if( (pos.y-particles_forms[(*i)->life]->h) < 600 && pos.y >0){
			cut.y = 0;
			cut.h = 600 - pos.y ;
		} 
		else 
			continue;

		*/

		//SDL_BlitSurface(particles_forms[(*i)->life],&cut, screen, &pos);
		SDL_BlitSurface(particles_forms[(*i)->life],NULL, screen, &pos);


	}

}

ParticleEngine::~ParticleEngine(){
	int i;
	for(i=0;i<256;i++)
		SDL_FreeSurface(particles_forms[i]);

	list<struct particle *>::iterator iter;
       	for( iter=particles_list->begin() ; iter!=particles_list->end() ;iter++)
		delete *iter;


	delete particles_list;

}
